package parserjc.jaccie;

import java.util.*;

/**
* Die Klasse von der die erzeugten Jourdan-Evaluatoren abgeleitet werden.
*/
public abstract class EvaluatorJourdan implements EvaluatorAction {

	//private TestFenster testFenster = new TestFenster();

	//der Syntaxbaum
    protected EvaluatorTree tree;

    //die Attribute
    private Vector<Vector<String>> attributes = new Vector<Vector<String>>();

    //true erm�glicht das evaluieren per Hand
    private boolean manipulateMode = false;
    //falls es dazu kommt, k�nnen get und set anders arbeiten
    private boolean evaluatePerHand = false;

    protected String activeRule;
    private String actSymbol;
    private boolean activeType = true;
    private Vector<StackAttribute> dependencies = null;
    private EvaluatorTree actTreeNode;

	//hier werden f�r die back()-Methode die ver�nderten Knoten-Attribute
    //als String mit folgender Notation... gemerkt
    //                Wurzel
    //              /   |   \
    //         Sohn0  Sohn1  Sohn2
    //        /    \           |
    //    Sohn0    Sohn1     Sohn0
    //      Attr0    Attr0     Attr0 <- "0.2.0:0"
    //               Attr1 <- "0.0.1:1"
    //
    //zus�tzlich werden stack - informarmationen gespeichert
    //above:<count> gibt an, wieviel neu zu bearbeitenden Attribute eingef�gt w.
    //under gibt an, dass im letzten Schritt ein Attribute berechnet wurde
	private Vector history = new Vector();

	//hier werden die angefangenen Schritte notiert
    //der Keller kann hier bis "ins Haus hochwachsen", da die alten
    //Stackinformationen f�r die back()-Methode gebraucht werden
    private Vector<StackAttribute> stack = new Vector();

    //hier werden die berechneten Werte gespeichert, die noch nicht
    //verarbeitet wurden
    private Vector values = new Vector();

	//bezeichnet die aktuelle (Erdgeschossh�he -> Kellerende, Hausanfang)
    private int stackPos = 0;

	//im ersten Schritt ist gesondert zu verfahren
    //(Attribute des Wurzelknotens werden in den Keller geschaft)
    private boolean firstStep = true;

	/**
    * Erzeugt einen neuen Evaluator mit dem Syntaxbaum tree.
    */
    public EvaluatorJourdan(EvaluatorTree tree) {
		this();
		this.setTree(tree);
    }

	/**
    * Erzeugt einen neuen Evaluator.
    */
    public EvaluatorJourdan() {
        addAttributes();
    }

	/**
    * F&uuml;gt die Attribute in eine interne Liste ein.
    * Wird durch die abgeleitete Klasse eingetragen.
    */
    protected abstract void addAttributes();

	/**
    * F&uuml;gt ein Attribut hinzu.
    */
	protected void addAttribute(String name, String type) {
        Vector<String> v = new Vector<String>();
        v.add(name);
        v.add(type);
        attributes.add(v);
    }

    /**
    * Setzt den zu evaluierenden Syntaxbaum.
    */
    public void setTree(EvaluatorTree tree) {
        this.tree = tree;
        reset();
    }

    /**
    * Setzt den zu evaluierenden Syntaxbaum.
    */
	public void setTree(String stringTree) {
        StringTokenizer st = new StringTokenizer(stringTree,"\n");
		if (st.hasMoreTokens()) tree = new EvaluatorTree(st.nextToken().trim());
        EvaluatorTree helpTree = tree;
        int count = 0;
        while (st.hasMoreTokens()) {
            String next = st.nextToken();
            StringTokenizer st2 = new StringTokenizer(next);
            int count2 = 0;
            for (count2=0; next.charAt(count2) == ' '; count2++);
            if ((count2 == count+2) && (st2.hasMoreTokens())) {
                EvaluatorTree nextTree = new EvaluatorTree(st2.nextToken());
                helpTree.addSon(nextTree);
                if (st2.hasMoreTokens()) {
                    String attribute = next.substring(next.indexOf((char)34)+1,next.lastIndexOf((char)34));
                    Vector<String> attr = new Vector<String>();
                    attr.addElement("string");
                    attr.addElement("0");
                    attr.addElement("done");
                    attr.addElement(attribute);
                    nextTree.getAttributes().addElement(attr);
                }
				count = count2;
                helpTree = nextTree;
            }
            else if ((count2 == count) && (st2.hasMoreTokens())) {
                EvaluatorTree nextTree = new EvaluatorTree(st2.nextToken());
                helpTree = helpTree.getParent();
                helpTree.addSon(nextTree);
                if (st2.hasMoreTokens()) {
                    String attribute = next.substring(next.indexOf((char)34)+1,next.lastIndexOf((char)34));
                    Vector<String> attr = new Vector<String>();
                    attr.addElement("string");
                    attr.addElement("0");
                    attr.addElement("done");
                    attr.addElement(attribute);
                    nextTree.getAttributes().addElement(attr);
                }
				count = count2;
                helpTree = nextTree;
            }
            else if ((count2 < count) && (st2.hasMoreTokens())) {
                EvaluatorTree nextTree = new EvaluatorTree(st2.nextToken());
				for (int i=0; i <= count-count2; i=i+2)
	                helpTree = helpTree.getParent();
                helpTree.addSon(nextTree);
                if (st2.hasMoreTokens()) {
                    String attribute = next.substring(next.indexOf((char)34)+1,next.lastIndexOf((char)34));
                    Vector<String> attr = new Vector<String>();
                    attr.addElement("string");
                    attr.addElement("0");
                    attr.addElement("done");
                    attr.addElement(attribute);
                    nextTree.getAttributes().addElement(attr);
                }
				count = count2;
                helpTree = nextTree;
            }
        }
        reset();
    }

	/**
    * F&uuml;gt die Attribute in den Syntaxbaum ein.
    */
    protected abstract void insertAttributes();

	/**
    * F&uuml;gt ein Attribut in den Baum ein.
    * Rekursiv in alle Knoten mit dem Namen nont.
    */
	protected void insertAttribute(EvaluatorTree tree, String nont, String attr) {
        if (tree.getName().equals(nont))
            tree.addAttribute(attr,getType(attr));
        for (int i=0; i < tree.getNumberOfSons(); i++)
            insertAttribute(tree.getSon(i),nont,attr);
    }

	/**
    * Liefert den Typen des Attributes,
    * falls es in den Attributen enthalten ist, sonst true.
    * @return true wenn synthetisiert
    * @return false wenn ererbt
    */
    private boolean getType(String attr) {
        for (int i=0; i < attributes.size(); i++)
            if (attributes.elementAt(i).elementAt(0).equals(attr))
                return (attributes.elementAt(i).elementAt(1).equals("1"));
        return true;
    }

	/**
    * Liefert den Wert eine Attributes.
    */
	protected Object get(String attribute) {
        //nur wenn normaler Ablauf, sonst kommen die Werte aus dem Baum
        if (!evaluatePerHand)
			//gibts das schon?
	        for (int i=values.size()-1; i >=0; i--) {
    	        StackAttribute help = (StackAttribute)values.elementAt(i);
        	    if (help.getRealName().equals(attribute)) {
            	    values.removeElementAt(i);
                    history.addElement(help);
                	return help.getValue();
	            }
    	    }
		//auch im normalen Ablauf kann - durch vorangegangene Abweichungen
        //verursacht durch den Nutzer - ein Attribut nicht im Wertekeller sein

		//Attribut wird aus dem Baum geholt

        //Attributnamen besorgen
        String attr = attribute.substring(attribute.lastIndexOf(".")+1);
        //Knotennamen besorgen
        String node = attribute.substring(0,attribute.lastIndexOf("."));

        //Knotenposition innerhalb der Regel
        int i = -1;
        StringTokenizer st = new StringTokenizer(activeRule);
        int j = 0;
        while ((st.hasMoreTokens()) && (i == -1)) {
            if (st.nextToken().equals(node)) i=j;
            j++;
        }
		//Knoten holen - unterscheiden, ob synthetisiert oder ererbt
        EvaluatorTree t = null;
		if (activeType) { //synthetisiert
			if (i == 0) { //linke Seite
				t = actTreeNode;
            }
            else if (i > 0) {
                t = actTreeNode.getSon(i-1);
            }
        }
        else { //ererbt
        	if (i == 0) {
            	t = actTreeNode.getParent();
        	}
        	else if (i > 0) {
            	t = actTreeNode.getParent().getSon(i-1);
        	}
        }
		//ist das Attribute schon berechnet?
        Vector attrs = t.getAttributes();
        for (int k=0; k < attrs.size(); k++)
            if (((String)((Vector)attrs.elementAt(k)).elementAt(0)).equals(
            	attr)) {
            	for (int l=0; l<values.size(); l++) {
                	//zur Sicherheit m�ssen die Attribute, die auch im
                    //Wertekeller sind entfernt werden...
                	StackAttribute help = (StackAttribute)values.elementAt(l);
                    if ((help.getTree() == t) && (help.getNumber() == k)) {
                        values.remove(help);
                        history.addElement(help);
                        return help.getValue();
                    }
            	}
                return ((Vector)attrs.elementAt(k)).elementAt(3);
        	}
		return null;
    }

    /**
    * Setzt den Wert eines Attributes.
    */
	protected void set(String attribute, Object toSet) {
        //Attributnamen besorgen
        StackAttribute help = null;
        if (stack.size() > stackPos)
            help = (StackAttribute)stack.elementAt(stackPos);
        if ((!evaluatePerHand) && (help != null) &&
            (help.getSelfName() != null) &&
            (help.getSelfName().equals(attribute))) {
            help.setValue(toSet);
            help.setState("done");
            values.addElement(help);
            stackPos++;
            return;
        }

        String attr = attribute.substring(attribute.lastIndexOf(".")+1);
        Vector attrs = actTreeNode.getAttributes();
        for (int k=0; k < attrs.size(); k++)
            if (((String)((Vector)attrs.elementAt(k)).elementAt(0)).equals(
            	attr)) {
            	((Vector)attrs.elementAt(k)).setElementAt("done",2);
            	((Vector)attrs.elementAt(k)).setElementAt(toSet,3);
        	}
        //in die Liste der berechneten Werte eintragen
    }

    /**
    * F&uuml;hrt den n&auml;chsten Schritt aus.
    * Implementation f&uuml;r EvaluatorAction-Interface.
    */
	public String nextStep() {
        String result = nextStep(tree);
		//testFenster.update(stack,stackPos,values,history);
        return result;
    }

    /**
    * F&uuml;hrt die Evaluierung durch.
    * Implementation f&uuml;r EvaluatorAction-Interface.
    */
    public String doAll() {
        String returnStr = "at work";
        while (returnStr.equals("at work"))
            returnStr = nextStep();
        return returnStr;
    }

    /**
    * Setzt den Evaluator zur�ck.
    * Implementation f&uuml;r EvaluatorAction-Interface.
    */
    public void reset() {
		insertAttributes();
        firstStep = true;
        stack.clear();
        history.clear();
        values.clear();
        stackPos = 0;
    }

	/**
    * Evaluiert genau ein berechenbares Attribut des Baumes.
    * (F&uuml;r die sensitive Steuerung.)
    * Implementation f&uuml;r EvaluatorAction-Interface.
    */
    public void evaluate(String address) {
        EvaluatorTree t = tree;
		StringTokenizer st = new StringTokenizer(
            address.substring(0,address.indexOf(":")),".");
        if (st.hasMoreTokens()) st.nextToken();
		while (st.hasMoreTokens())
            t = t.getSon(Integer.parseInt(st.nextToken()));
        int k = Integer.parseInt(address.substring(address.indexOf(":")+1));
		Vector attr = (Vector)t.getAttributes().elementAt(k);
        //handelt es sich um das Attribut, das eh gleich dran w�r?
		StackAttribute help;
        if (stack.size() > stackPos) {
			help = stack.elementAt(stackPos);
	        if ((help.getTree() == t) && (help.getNumber() == k)) {
    	        if (!help.getState().endsWith("started")) nextStep(tree);
        	    nextStep(tree); //dann mach es...
            	//testFenster.update(stack,stackPos,values,history);
	            return;
            }
        }
        help = new StackAttribute("",attr,"",t,k);

        String state = help.getState();
        if ((state != null) &&			//kann berechnet werden?
            (state.startsWith("ready"))) {
            //dabei kommen die aus dem Wertekeller genommenen Attribute auf
            //die history
            evaluatePerHand = true;
	        evaluate(help);
            evaluatePerHand = false;
            //das letzte was auf dem Stack landen soll, ist die Information
            //�ber die verrichtete T�tigkeit...
	        history.addElement(state+"+"+help.getTree().getAddress()+
                ":"+help.getNumber());
            //testFenster.update(stack,stackPos,values,history);
        }
    }

    /**
    * Setzt den Evaluator einen Schritt zur&uuml;ck.
    * Implementation f&uuml;r EvaluatorAction-Interface.
    */
    public void back() {
        int size = history.size();
        //falls es der letzte Schritt ist, der r�ckg�ngig gemacht werden soll...
        if (size == 0) {
            if (!firstStep) reset(); //zur�cksetzen
            return;
        }
		String entry = (String)history.elementAt(size-1);
        history.removeElementAt(size-1);
        //im letzten Schritt wurde das Attribut berechnet und im Wertekeller
        //gespeichert
        if (entry.equals("under")) {
            //Anfang des Attributkellers hochsetzen
   	        stackPos--;
            //oberstes Attribut von Attributkeller vom Wertekeller nehmen und
            //den Wert des Attributes zur�cksetzen
       	    StackAttribute help = stack.elementAt(stackPos);
           	help.setState("started");
       	    help.setValue(null);
   	        values.remove(help);
            //ggf. den Status korrigieren, falls berechenbar (ebenso Umgebung)
       	    if (manipulateMode) checkForReady(help.getTree());
            boolean ok = true;
            //gespeicherte Attribute kommen wieder in den Wertekeller
            while (ok) {
				Object o = history.elementAt(history.size()-1);
    	        if (o instanceof StackAttribute) {
	    		    history.removeElementAt(history.size()-1);
            	    values.addElement(o);
    			}
    			else ok = false;
            }
        }
        //das Attribut war im letzten Schritt schon berechnet und wurde in
        //den Wertekeller kopiert. Es muss wieder in den Attributkeller zur�ck.
        else if (entry.equals("under2")) {
            //Anfang des Attributkellers hochsetzen.
   	        stackPos--;
            //oberstes Attribut vom Attributkeller vom Wertekeller nehmen
       	    StackAttribute help = stack.elementAt(stackPos);
            values.removeElement(help);
            //da hier keine sichtbaren Ver�nderungen stattfinden, wird gleich
            //noch ein Schritt zur�ckgegangen
            back();
            return;
        }
        //Um ein Attribut zu berechnen waren weitere Attribute n�tig, die auf
        //den Attributkeller getan wurden. Diese m�ssen entfernt werden.
		else if (entry.startsWith("above:")) {
            //Anzahl der eingef�gten Attribute holen
       	    int count = Integer.parseInt(entry.substring(6));
            //der Anzahl entsprechend viele entfernen
            for (int i=0; i < count; i++) {
	            StackAttribute help = stack.elementAt(stackPos);
       	        stack.removeElementAt(stackPos);
   	        }
            //Status wieder auf "undef" zur�cksetzen
            stack.elementAt(stackPos).setState(null);
            //ggf. den Status korrigieren, falls berechenbar (ebenso Umgebung)
            if (manipulateMode) checkForReady(
                stack.elementAt(stackPos).getTree());
       	}
        //Nur relavant f�r den ManipulateMode.
        //Es wurde ein auswertbares Attribut ausgewertet. Es wird zurpckgesetzt
        //und der vorherige Status gesetzt.
		else if (entry.startsWith("ready")) {
            //vorherigen Status holen
            String state = entry.substring(0,entry.indexOf("+"));
            entry = entry.substring(entry.indexOf("+")+1);
            //Adresse des Knotens holen
            String node = entry.substring(0,entry.indexOf(":"));
            //Nummer des Attributes holen
            int k = Integer.parseInt(entry.substring(entry.indexOf(":")+1));
            EvaluatorTree t = getTree(node);
            //zur�cksetzen
            ((Vector)t.getAttributes().elementAt(k)).
                setElementAt(state,2);
            ((Vector)t.getAttributes().elementAt(k)).
                setElementAt(null,3);
            //ggf. den Status korrigieren, falls berechenbar (ebenso Umgebung)
            checkForReady(t);
            boolean ok = true;
            //gespeicherte Attribute kommen wieder in den Wertekeller
            while (ok) {
				Object o = history.elementAt(history.size()-1);
    	        if (o instanceof StackAttribute) {
	    		    history.removeElementAt(history.size()-1);
            	    values.addElement(o);
    			}
    			else ok = false;
            }
        }
        //testFenster.update(stack,stackPos,values,history);
    }

	/**
    * Was ist jetzt noch/wieder berechenbar?
    */
    private void checkForReady(EvaluatorTree helpTree) {
        //kann nur beim Vater,
		if (helpTree.getParent() != null) {
            checkNodeIfPossible(helpTree.getParent());
			//bei den Br�dern geschehen
    	    for (int j=0; j < helpTree.getParent().getNumberOfSons(); j++)
        	    checkNodeIfPossible(helpTree.getParent().getSon(j));
        }
		else {
	        //beim Knoten selbst
       	    checkNodeIfPossible(helpTree);
        }
		//bei den S�hnen
        for (int j=0; j < helpTree.getNumberOfSons(); j++)
            checkNodeIfPossible(helpTree.getSon(j));
    }

    //f�hrt den n�chsten Schritt durch
    private String nextStep(EvaluatorTree tree) {
        //erstmalig den Baum nach auswertbaren Attributen durchsuchen
        //ebenfalls werden die Attribute der Wurzel angefangen
		if (firstStep) {
            firstStep = false;
            if (manipulateMode) checkAllIfPossible(tree);
            Vector attribs = tree.getAttributes();
            for (int i=attribs.size()-1; i >=0; i--) {
				if (((Vector)attribs.elementAt(i)).elementAt(2) == null) {
                    StackAttribute help = new StackAttribute("A1.a",
						(Vector)attribs.elementAt(i), "A1 A2 A3", tree, i);
    	            stack.insertElementAt(help,stackPos);
                }
            }
            return "at work"; //noch nicht fertig
        }
        //gibt es noch etwas zu tun?
        if (stack.size() == stackPos) return "complete";
        //hole Attribut samt Knoten vom Stack
        StackAttribute attr = stack.elementAt(stackPos);
        EvaluatorTree t = attr.getTree();
        int number = attr.getNumber();
        if ((attr.getState() == null) ||
            ((manipulateMode) && (attr.getState().equals("ready")))) {
            //markiere es als angefangen
            if (manipulateMode && (attr.getState() != null) &&
                attr.getState().equals("ready"))
                attr.setState("ready&started");
            else attr.setState("started");
        	//dann hole ben�tigte Attribute
            dependencies = new Vector<StackAttribute>();
			checkAttributeIfPossible(t,number);
            int count = 0;
			for (int i=dependencies.size()-1; i >= 0; i--) {
                StackAttribute att = dependencies.elementAt(i);
                //alle Attribute von denen es abh�ngig ist, kommen auf den Stack
                if ((att.getState() == null) ||
                	!(att.getState().equals("started"))) {
		            //f�ge sie in den Stack ein
                    stack.insertElementAt(att,stackPos);
                    count++;
                }
                //sonst gibt es einen Zyklus
                else return "cycle";
            }
			dependencies = null; //wichtig, sonst arbeitet check() nicht!
            //merken, wieviele Attribute auf den Stack kamen (f�r back()).
            history.addElement("above:"+count);
        }
        //falls es schon gestartet war, so sind alle ben�tigten Attribute
        //bereits berechet worden...
        else if ((attr.getState().equals("started")) ||
                 (attr.getState().equals("ready&started"))) {
        	//dann berechne es und stackPos++;
			evaluate(attr);
            history.addElement("under");
        }
        //oder ist es fertig (done)
		else if (attr.getState().equals("done")) {
			//�berspringen
            values.addElement(attr);
            stackPos++;
            history.addElement("under2");
			return nextStep(tree);
        }
        //mache weiter
        return "at work";
    }

    //gibt den Konten mit der Adresse zur�ck
    private EvaluatorTree getTree(String address) {
        EvaluatorTree t = tree;
		StringTokenizer st = new StringTokenizer(address,".");
        if (st.hasMoreTokens()) st.nextToken();
        while (st.hasMoreTokens())
            t = t.getSon(Integer.parseInt(st.nextToken()));
        return t;
    }

	//evaluiert genau ein Attribut -> sensitive Steuerung
	private EvaluatorTree evaluate(StackAttribute attr) {
        //Auswertungskontext zusammensuchen...
        actTreeNode = attr.getTree();
        //f�r synthetisierte Attribute...
        if (attr.getType().equals("1")) {
            activeType = true;
            activeRule = actTreeNode.getName();
            for (int j=0; j < actTreeNode.getNumberOfSons(); j++)
                activeRule = activeRule+" "+actTreeNode.getSon(j).getName();
            activeRule = checkDoubleNames(activeRule);
            int index = activeRule.indexOf(" ");
            if (index == -1) actSymbol = activeRule;
            else actSymbol = activeRule.substring(0,index);
        }
		else {
            activeType = false;
            activeRule = actTreeNode.getParent().getName();
            int pos=0;
            for (int j=0; j < actTreeNode.getParent().getNumberOfSons(); j++) {
                activeRule = activeRule+" "+
                    actTreeNode.getParent().getSon(j).getName();
                if (actTreeNode.getParent().getSon(j) == actTreeNode) pos=j;
            }
            //Doppelnamen nummerieren
            activeRule = checkDoubleNames(activeRule);
            //jetzigen Symbolnamen raussuchen
            StringTokenizer st = new StringTokenizer(activeRule);
            for (int j=0; j < pos+2; j++)
                actSymbol = st.nextToken();
        }

		attr.setSelfName(actSymbol+"."+attr.getName());
        attr.setSelfRule(activeRule);
		//berechne jetzt den Wert des Attributes
		calculate(actSymbol+"."+attr.getName());

		//ist jetzt mehr berechenbar geworden?
        if (manipulateMode) checkForReady(actTreeNode);

		return actTreeNode;
    }

    //druchsucht nach berechenbaren Attributen den ganzen Baum
	private void checkAllIfPossible(EvaluatorTree t) {
        checkNodeIfPossible(t);
	    for (int i=0; i < t.getNumberOfSons(); i++) {
            checkAllIfPossible(t.getSon(i));
        }
    }

    //pr�ft alle Attribute im Konten, ob berechenbar
	private void checkNodeIfPossible(EvaluatorTree t) {
		//geh alle Attribute des Knotens durch...
		for (int i=0; i < t.getAttributes().size(); i++)
			checkAttributeIfPossible(t,i);
    }

    //pr�ft ein Attribut, ob berechenbar
	private void checkAttributeIfPossible(EvaluatorTree t, int number) {
		int i = number;
        Vector attr = (Vector)t.getAttributes().elementAt(i);
		//nur, wenn noch nicht "done" ist etwas zu tun...
        if ((attr.elementAt(2) == null) ||
            (!attr.elementAt(2).equals("done"))) {
            //Auswertungskontext zusammensuchen...
   	        //f�r synthetisierte Attribute
			if (attr.elementAt(1).equals("1")) {
           	    activeType = true;
				activeRule = t.getName();
	            for (int j=0; j < t.getNumberOfSons(); j++)
                    activeRule = activeRule+" "+t.getSon(j).getName();
				activeRule = checkDoubleNames(activeRule);
           	    actTreeNode = t;
                int index = activeRule.indexOf(" ");
                if (index == -1) actSymbol = activeRule;
               	else actSymbol = activeRule.substring(0,index);
	        }
            //f�r ererbte Attribute
       	    else {
          	    activeType = false;
               	activeRule = t.getParent().getName();
	            int pos=0;
                for (int j=0; j < t.getParent().getNumberOfSons(); j++){
       	            activeRule = activeRule+" "+
           	          	t.getParent().getSon(j).getName();
	                if (t.getParent().getSon(j) == t) pos=j;
                }
       	        //bei Doppelname erfolgt Nummerieren
				activeRule = checkDoubleNames(activeRule);
	            //den jetzt g�ltigen Symbol-Namen raussuchen
                StringTokenizer st = new StringTokenizer(activeRule);
       	        for (int j=0; j < pos+2; j++)
           	        actSymbol = st.nextToken();
               	//den aktuellen Knoten setzen
	            actTreeNode = t;
            }
       		if (dependencies != null) {
				checkIfPossible(actSymbol+"."+(String)attr.elementAt(0));
                return;
       		}
       	    //Setze Attribute auf berechenbar
			if (checkIfPossible(actSymbol+"."+(String)attr.elementAt(0))) {
				if (attr.elementAt(2) == null)
	                attr.setElementAt("ready",2);
               	else if (attr.elementAt(2).equals("started"))
	                attr.setElementAt("ready&started",2);
            }
       	    //Setze Attribute zur�ck
            else {
				if ((attr.elementAt(2) != null) &&
                    (attr.elementAt(2).equals("ready")))
	                attr.setElementAt(null,2);
				else if ((attr.elementAt(2) != null) &&
                    (attr.elementAt(2).equals("ready&started")))
	                attr.setElementAt("started",2);
            }
        }
    }

	/**
    * F�gt bei doppelten Symbolnamen Nummerierung ein.
    * Folge -> Folge Ziffer    wird zu:   Folge1 -> Folge2 Ziffer
    */
	private String checkDoubleNames(String rule) {
        Vector help = new Vector();
        Vector symbols = new Vector();
        StringTokenizer st = new StringTokenizer(rule);
        while(st.hasMoreTokens()) {
            String symbol = st.nextToken();
            if (symbols.contains(symbol)) help.add(symbol);
            symbols.add(symbol);
        }
        for (int i=0; i < help.size(); i++) {
            int c = 1;
            for (int j=0; j < symbols.size(); j++) {
                if (symbols.elementAt(j).equals(help.elementAt(i))) {
                    symbols.setElementAt((String)help.elementAt(i)+c,j);
                    c++;
                }
            }
        }
        String returnString = "";
        for (int i=0; i < symbols.size(); i++) {
            returnString = returnString+(String)symbols.elementAt(i)+" ";
        }
        return returnString.substring(0,returnString.length()-1);
    }

	protected boolean check(String attribute) {
        //Attributnamen besorgen
        String attr = attribute.substring(attribute.lastIndexOf(".")+1);
        //Knotennamen besorgen
        String node = attribute.substring(0,attribute.lastIndexOf("."));

        //Knotenposition innerhalb der Regel
        int i = -1;
        StringTokenizer st = new StringTokenizer(activeRule);
        int j = 0;
        while ((st.hasMoreTokens()) && (i == -1)) {
            if (st.nextToken().equals(node)) i=j;
            j++;
        }
		//Knoten holen - unterscheiden, ob synthetisiert oder ererbt
        EvaluatorTree t = null;
		if (activeType) { //synthetisiert
			if (i == 0) { //linke Seite
				t = actTreeNode;
            }
            else if (i > 0) {
                t = actTreeNode.getSon(i-1);
            }
        }
        else { //ererbt
        	if (i == 0) {
            	t = actTreeNode.getParent();
        	}
        	else if (i > 0) {
            	t = actTreeNode.getParent().getSon(i-1);
        	}
        }
		//ist das Attribute schon berechnet?
        Vector attrs = t.getAttributes();

        //kleiner Trick, damit bekannt wird, von welchen Attributen etwas
        //abh�ngig ist
        if (dependencies != null) {
	        for (int k=0; k < attrs.size(); k++)
    	        if (((String)((Vector)attrs.elementAt(k)).elementAt(0)).equals(
        	    	attr)) {
                	StackAttribute help = new StackAttribute(
                        attribute,(Vector)attrs.elementAt(k), activeRule, t, k);
            		dependencies.addElement(help);
					return true;
            	}
            return true; //damit alle ausgewertet werden m�ssen
        }

        for (int k=0; k < attrs.size(); k++)
            if (((String)((Vector)attrs.elementAt(k)).elementAt(0)).equals(
            	attr)) {
            	return ((((Vector)attrs.elementAt(k)).elementAt(2) != null) &&
                    (((Vector)attrs.elementAt(k)).elementAt(2).equals("done")));
        	}
        return false;
    }

    //Die Implementation wird erzeugt.
    protected abstract boolean checkIfPossible(String attr);

    //Die Implementation wird erzeugt.
    protected abstract void calculate(String attr);

	/**
    * Gibt den Baum im derzeitigen Bearbeitungsstatus zur&uuml;ck.
    */
    public EvaluatorTree getTree() {return tree;}
    /**
    * Gibt die Attribute als Vectoren in einem Vector zur&uuml;ck.
    */
    public Vector getAttributes() {return attributes;}

	/**
    * F&uuml;hrt den Evaluator aus.
    */
    public String start() {
        insertAttributes();
        return doAll();
    }

    //druchsucht nach berechenbaren Attributen den ganzen Baum und setzt den
    //Status zur�ck  ready -> null
    //               ready&started -> started
	private void clearReadyStates(EvaluatorTree t) {
        Vector attrs = t.getAttributes();
	    for (int i=0; i < attrs.size(); i++) {
            String state = (String)((Vector)attrs.elementAt(i)).elementAt(2);
            if (state != null) {
                if (state.equals("ready"))
                    ((Vector)attrs.elementAt(i)).setElementAt(null,2);
                else if (state.equals("ready&started"))
                    ((Vector)attrs.elementAt(i)).setElementAt("started",2);
            }
        }
	    for (int i=0; i < t.getNumberOfSons(); i++) {
            clearReadyStates(t.getSon(i));
        }
    }

    /**
    * Schaltet in den "Hand-Modus" und wieder heraus.
    * @return true, wenn danach Hand-Modus eingeschalten ist.
    */
    public boolean switchHandMode() {
        if (manipulateMode) {
			//ausschalten
			clearReadyStates(tree);
            manipulateMode = false;
            return false;
        }
        else {
            //einschalten
            manipulateMode = true;
            checkAllIfPossible(tree);
            return true;
        }
    }

}
